
'use strict';

/**
	Part of Zombie Navigator
	Copyright © 2015  Zombie Navigator Developers
	
	@file
	@module
	@license AGPL-3.0+
*/


/* Addon SDK dependencies */
const _sdkURL = require('sdk/url');


/* Exported APIs */

/**
	@public
	@method
	@param {string} path
	@returns {string}
*/
const filenameToURI = path => {
	path = path + '';
	
	const sdkURL = _sdkURL;
	
	try {
		return sdkURL.fromFilename(path) + '';
	} catch (e) {
		throw new Error(e + '');
	}
};

/**
	Strictly resolves a URI (or IRI) reference, the standard way
	@public
	@method
	@param {string} base
	@param {string} ref
	@returns {string}
*/
const resolve = (base, ref) => {
	const parse = uriRef => {
		const [, scheme, authority, path, query, fragment] = (uriRef + '')
		.match(new RegExp('^([^:/?#]+:)?(//[^/?#]*)?([^?#]*)(\\?[^#]*)?(#.*)?$'));
		return {
			scheme: scheme
			, authority: authority
			, path: path
			, query: query
			, fragment: fragment
		};
	};
	
	const compose = ({scheme, authority, path, query, fragment}) => {
		return [
			scheme || ''
			, authority || ''
			, path
			, query || ''
			, fragment || ''
		].join('');
	};
	
	const removeDotSegments = path => {
		const input = path.split('/');
		const output = [];
		
		while (input.length) {
			if ('.' === input[0] || '..' === input[0]) {
				input.shift();
				continue;
			}
			
			if ('' === input[0]) {
				if (2 > input.length) {
					break;
				}
				
				if ('.' === input[1]) {
					input.shift();
					input[0] = '';
					if (2 > input.length) {
						input.push('');
					}
					continue;
				}
				
				if ('..' == input[1]) {
					input.shift();
					input[0] = '';
					if (2 > input.length) {
						input.push('');
					}
					output.pop();
					continue;
				}
				
				input.shift();
				if (!output.length) {
					output.push('');
				}
			}
			
			output.push(input.shift());
			input.unshift('');
		}
		
		return output.join('/');
	};
	
	const mergePaths = (basePath, refPath) => {
		const pos = basePath.lastIndexOf('/');
		if (0 > pos) {
			return refPath;
		}
		
		return [basePath.slice(0, 1 + pos), refPath].join('');
	};
	
	
	[base, ref] = [base, ref].map(parse);
	
	const resolved = {};
	if ('undefined' != typeof ref.scheme) {
		resolved.scheme = ref.scheme;
		resolved.authority = ref.authority;
		resolved.path = ref.path;
		resolved.query = ref.query;
	} else {
		if ('undefined' != typeof ref.authority) {
			resolved.authority = ref.authority;
			resolved.path = removeDotSegments(ref.path);
			resolved.query = ref.query;
		} else {
			if ('' === ref.path) {
				resolved.path = base.path;
				if ('undefined' != typeof ref.query) {
					resolved.query = ref.query;
				} else {
					resolved.query = base.query;
				}
			} else {
				if ('/' === ref.path[0]) {
					// absolute path
					resolved.path = removeDotSegments(ref.path);
				} else {
					// relative path
					resolved.path = removeDotSegments(mergePaths(base.path, ref.path));
				}
				
				resolved.query = ref.query;
			}
			
			resolved.authority = base.authority;
		}
		
		resolved.scheme = base.scheme;
	}
	
	resolved.fragment = ref.fragment;
	
	return compose(resolved);
};


/* Exports */
exports.filenameToURI = filenameToURI;
exports.resolve = resolve;


// vim: ts=4 noet ai

